//
// Created by Huafv on 2024/10/11.
//

#include <pthread.h>
#include <stdio.h>
#include "bt_phybusif_h4.h"
#include "ringbuffer.h"
#include "bt_common.h"
#include "bt_hci.h"
#include "bt_snoop.h"
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>

#define PHY_BUS_IF_NAME "/dev/ttyUSB0"

/****************************** Defines ***************************/
#define BT_RX_BUF_SIZE  (8 * 1024)
#define BT_DMA_BUF_SIZE	(4 * 1024)

uint8_t bt_rx_buf[BT_RX_BUF_SIZE] =      { 0 };
uint8_t bt_dma_rx_buf[BT_DMA_BUF_SIZE] = { 0 };

struct ringbuffer bt_ring_buf;

/* create thread to receive bluetooth contorller data */
pthread_t thread_rx_id;

/* PHY Bus interface struct */
struct phybusif_cb uart_if;

/* uart thread lock */
uint8_t uart_thread_process = 1;

/************************* Function prototype *************************/
void *uart_rx_thread(void *data);
void uart_bt_send(uint8_t *buf,uint16_t len);

/**
 * @brief hardware uart init
 * @param baud_rate
 * @return
 */
uint8_t hw_uart_bt_init(uint32_t baud_rate)
{
    speed_t baudrate;
    int flags = O_RDWR | O_NOCTTY;

    struct termios toptions;
    if(baud_rate == 115200)
        baudrate =  B115200;
    else
        baudrate =  B921600;

    printf("phybusif_open %s\n", PHY_BUS_IF_NAME);

    uart_if.phyuart_fd = open(PHY_BUS_IF_NAME, flags);
    if (uart_if.phyuart_fd == -1)
    {
        printf("ERROR:Unable to open port %s\n",PHY_BUS_IF_NAME);
        return -1;
    }

    printf("uart_if.phyuart_fd %d\n",uart_if.phyuart_fd);
    if (tcgetattr(uart_if.phyuart_fd, &toptions) < 0)
    {
        printf("ERROR:Couldn't get term attributes\n");
        return -1;
    }

    cfmakeraw(&toptions);

    // 8N1
    toptions.c_cflag &= ~CSTOPB;
    toptions.c_cflag |= CS8;

    toptions.c_cflag |= CREAD | CLOCAL | CRTSCTS;
    toptions.c_iflag &= ~(IXON | IXOFF | IXANY);
    toptions.c_cflag &= ~PARENB;

    toptions.c_cc[VMIN]  = 1;
    toptions.c_cc[VTIME] = 0;

    if(tcsetattr(uart_if.phyuart_fd, TCSANOW, &toptions) < 0)
    {
        printf("ERROR:Couldn't set term attributes\r\n");
        return -1;
    }

    if (tcgetattr(uart_if.phyuart_fd, &toptions) < 0)
    {
        printf("ERROR:Couldn't get term attributes\r\n");
        return -1;
    }

    cfsetospeed(&toptions, baudrate);
    cfsetispeed(&toptions, baudrate);


    if( tcsetattr(uart_if.phyuart_fd, TCSANOW, &toptions) < 0)
    {
        printf("ERROR:Couldn't set term attributes\r\n");
        return -1;
    }

    return 0;

}

/* Thread handle */
pthread_t thread_rx_id;

/**
 * open PHY BUS Interface
 * @param baud_rate
 */
void phybusif_open(uint32_t baud_rate)
{
    /* Thread lock open */
    uart_thread_process = 1;

    /* create ringbuffer to receive bluetooth contorller data*/
    ringbuffer_init(&bt_ring_buf,bt_rx_buf,BT_RX_BUF_SIZE);

    /* to init hardware uart */
    hw_uart_bt_init(baud_rate);

    /* create thread to receive data */
    pthread_create(&thread_rx_id, NULL, uart_rx_thread, NULL);
}

/**
 * @brief uart receive data while thread
 * @param data
 * @return
 */
void *uart_rx_thread(void *data)
{
    // add lock
    while(uart_thread_process)
    {
        fd_set read_fd;
        int result = 0;
        struct timeval tv;
        tv.tv_sec = 1; /* 1s */
        tv.tv_usec = 0;

        /* monitor uart rx */
        FD_ZERO (&read_fd);
        FD_SET (uart_if.phyuart_fd, &read_fd);

        if ((result = select (1 + uart_if.phyuart_fd, &read_fd, NULL, NULL, &tv)) == -1)
        {
            printf("ERROR:file[%s],function[%s],line[%d] select fail\r\n",__FILE__,__FUNCTION__,__LINE__);
        }

        if(result > 0 && FD_ISSET ( uart_if.phyuart_fd, &read_fd))
        {

            int read_result = read(uart_if.phyuart_fd, bt_dma_rx_buf, BT_DMA_BUF_SIZE);

            if(ringbuffer_space_left(&bt_ring_buf) > read_result){
                ringbuffer_put(&bt_ring_buf,bt_dma_rx_buf,read_result);
            }
            else{
                printf("ERROR:file[%s],function[%s],line[%d] ring buffer left %d < %d\r\n",__FILE__,__FUNCTION__,__LINE__,ringbuffer_space_left(&bt_ring_buf),read_result);
            }

        }
    }

    pthread_exit((void *)0);
}

/**
 * @brief PHY Bus Interface input
 * @param cb
 * @return
 */
err_t phybusif_input(struct phybusif_cb *cb)
{
    static uint8_t read_buffer[64] = {0};
    while(!ringbuffer_is_empty(&bt_ring_buf))
    {
#if 0   /* this is to get data Test*/
        {
            static uint8_t  read_buffer[32] = {0};
            static uint32_t read_len = 0;
            read_len = ringbuffer_get(&bt_ring_buf, read_buffer, sizeof (read_buffer));
            if(read_len > 0){
                ringbuffer_print(&bt_ring_buf);
                for(int i = 0; i < read_len; i++){
                    printf("0x%x ", read_buffer[i]);
                }
                printf("\r\n");
            }
        }
#endif
        switch (cb->state) {
            case W4_PACKET_TYPE:
                uint8_t packet_type = 0;
                ringbuffer_get(&bt_ring_buf, &packet_type, 1);
                printf("PACKET TYPE : %d \r\n", packet_type);
                switch(packet_type)
                {
                    case PHYBUSIF_PACKET_TYPE_EVT:
                    {
                        cb->state = W4_EVENT_HDR;
                        break;
                    }
                    case PHYBUSIF_PACKET_TYPE_ACL_DATA:
                    {
                        cb->state = W4_ACL_HDR;
                        break;
                    }
                    default:
                        break;
                }
                break;
            case W4_EVENT_HDR:
                if(ringbuffer_len(&bt_ring_buf) < HCI_EVT_HDR_LEN)
                {

                }

                ringbuffer_get(&bt_ring_buf, read_buffer, HCI_EVT_HDR_LEN);
                cb->evhdr = (hci_evt_hdr_t *)read_buffer;
                cb->state = W4_EVENT_PARAM;
                break;
            case W4_ACL_HDR:
                if(ringbuffer_len(&bt_ring_buf) < HCI_ACL_HDR_LEN)
                {
//                    return BT_ERR_BUF;
                }

                break;
            case W4_EVENT_PARAM:
                ringbuffer_get(&bt_ring_buf, read_buffer + HCI_EVT_HDR_LEN, cb->evhdr->len);
#if BT_ENABLE_SNOOP > 0
                bt_snoop_write(BT_SNOOP_PACKET_TYPE_EVT,1,read_buffer,cb->evhdr->len + HCI_EVT_HDR_LEN);
#endif
                break;

            case W4_ACL_DATA:
#if BT_ENABLE_SNOOP > 0
                //bt_snoop_write(BT_SNOOP_PACKET_TYPE_ACL_DATA,1,NULL,cb->aclhdr->len+HCI_ACL_HDR_LEN);
#endif
                break;

            default:
                break;
        }
    }
    return BT_ERR_OK;
}


/**
 * UART send Data
 * @param buf data
 * @param len
 */
void uart_bt_send(uint8_t *buf, uint16_t len)
{
    bt_snoop_write(buf[0], 0, &buf[1], len - 1);
    write(uart_if.phyuart_fd, buf,len);
}
